/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Region from '../../Region';
import Identifier from '../../Identifier';
import bluetooth from '@ohos.bluetooth';
import BeaconParser from '../../BeaconParser'
import ScanFilterData from './ScanFilterData'

export default class ScanFilterUtils {
  public constructor() {
  }

  public createWildcardScanFilters(): Array< /*bluetooth.ScanFilter*/
  any> {
    let scanFilters: Array< /*bluetooth.ScanFilter*/
    any> = new Array();
    return scanFilters;
  }

  public createScanFilterDataForBeaconParser(beaconParser: BeaconParser, identifiers: Array<Identifier>): Array<ScanFilterData> {
    let scanFilters: Array<ScanFilterData> = new Array<ScanFilterData>();
    let typeCode: number = beaconParser.getMatchingBeaconTypeCode();
    let startOffset: number = beaconParser.getMatchingBeaconTypeCodeStartOffset();
    let endOffset: number = beaconParser.getMatchingBeaconTypeCodeEndOffset();
    let typeCodeBytes: Array<number> = BeaconParser.longToByteArray(typeCode, endOffset - startOffset + 1, true);
    let manufacturers: Array<number> = beaconParser.getHardwareAssistManufacturers()
    if (identifiers != null && identifiers.length > 0 && identifiers[0] != null && beaconParser.getMatchingBeaconTypeCode() == 0x0215) {
      for (let i = 0; i < manufacturers.length; i++) {
        let manufacturer = manufacturers[i]
        let sfd: ScanFilterData = new ScanFilterData();
        sfd.manufacturer = manufacturer;
        let length: number = 18;
        if (identifiers.length == 2) {
          length = 20;
        }
        if (identifiers.length == 3) {
          length = 22;
        }
        sfd.filter = new Array(length);
        sfd.filter[0] = typeCodeBytes[0];
        sfd.filter[1] = typeCodeBytes[1];
        let idBytes: Array<number> = identifiers[0].toByteArray();
        for (let i = 0; i < idBytes.length; i++) {
          sfd.filter[i+2] = idBytes[i];
        }
        if (identifiers.length > 1 && identifiers[1] != null) {
          idBytes = identifiers[1].toByteArray();
          for (let i = 0; i < idBytes.length; i++) {
            sfd.filter[i+18] = idBytes[i];
          }
        }
        if (identifiers.length > 2 && identifiers[2] != null) {
          idBytes = identifiers[2].toByteArray();
          for (let i = 0; i < idBytes.length; i++) {
            sfd.filter[i+20] = idBytes[i];
          }
        }
        sfd.mask = new Array()
        for (let i = 0; i < length; i++) {
          sfd.mask[i] = 0xff;
        }
        sfd.serviceUuid = null;
        sfd.serviceUuid128Bit = new Array();
        scanFilters.push(sfd);
        return scanFilters;
      }
    }
    for (let i = 0; i < manufacturers.length; i++) {
      let manufacturer = manufacturers[i]
      let sfd: ScanFilterData = new ScanFilterData();
      let serviceUuid: number = beaconParser.getServiceUuid();
      let length: number = endOffset + 1 - 2;
      let filter: Array<number> = new Array();
      let mask: Array<number> = new Array();
      if (length > 0) {
        filter = new Array(length);
        mask = new Array(length);
        for (let layoutIndex = 2; layoutIndex <= endOffset; layoutIndex++) {
          let filterIndex = layoutIndex - 2;
          if (layoutIndex < startOffset) {
            filter[filterIndex] = 0;
            mask[filterIndex] = 0;
          } else {
            filter[filterIndex] = typeCodeBytes[layoutIndex-startOffset];
            mask[filterIndex] = 0xff;
          }
        }
      }
      sfd.manufacturer = manufacturer;
      sfd.filter = filter;
      sfd.mask = mask;
      sfd.serviceUuid = serviceUuid;
      sfd.serviceUuid128Bit = beaconParser.getServiceUuid128Bit();
      scanFilters.push(sfd);
    }
    return scanFilters;
  }

  public createScanFiltersForBeaconParsers(beaconParsers: Array<BeaconParser>, regions?: Array<Region>): Array< /*bluetooth.ScanFilter*/
  any>  {
    let nonNullRegions: Array<Region> = new Array();
    if (regions == null) {
      nonNullRegions.push(null);
    }
    else {
      nonNullRegions.concat(regions);
    }

    let scanFilters: Array< /*bluetooth.ScanFilter*/
    any> = new Array();
    for (let i = 0; i < nonNullRegions.length; i++) {
      let region = nonNullRegions[i]
      for (let j = 0; j < beaconParsers.length; j++) {
        let beaconParser = beaconParsers[j]
        let sfds: Array<ScanFilterData> = this.createScanFilterDataForBeaconParser(beaconParser, region == null ? null : region.getIdentifiers());
        for (let x = 0; x < sfds.length; x++) {
          let sfd: ScanFilterData = sfds[x]
          //          let scanFilter: /*bluetooth.ScanFilter*/ any =  new bluetooth.ScanFilter();
          let scanFilter = {}
          if (sfd.serviceUuid != null) {
            // Use a 16 bit service UUID in a 128 bit form
            let serviceUuidString: string = "0000" + this.serviceUuidFormat(sfd.serviceUuid)
            + "-0000-1000-8000-00805f9b34fb"
            //            scanFilter.serviceUuid = serviceUuidString
            scanFilter = {
              'serviceUuid': serviceUuidString
            };
          }
          else if (sfd.serviceUuid128Bit.length != 0) {
            let serviceUuidString: string = Identifier.fromBytes(sfd.serviceUuid128Bit, 0, 16, true).toString();
            //            scanFilter.serviceUuid = serviceUuidString
            scanFilter = {
              'serviceUuid': serviceUuidString
            };
          }
          else {
            //            scanFilter.serviceUuid = null;
            scanFilter = {
              'serviceUuid': null
            };
          }
          scanFilters.push(scanFilter);
        }
      }
    }
    return scanFilters;
  }

  private serviceUuidFormat(serviceUuid: number): string {
    let formatServiceUuid: string = serviceUuid.toString()
    if (formatServiceUuid.length > 4) {
      formatServiceUuid = formatServiceUuid.substr(0, 4)
    } else {
      let zeros: number = 4 - formatServiceUuid.length
      for (let index = 0; index < zeros; index++) {
        formatServiceUuid = "0" + formatServiceUuid
      }
    }
    return formatServiceUuid
  }
}